%%%-------------------------------------------------------------------
%%% @author liuwentao
%%% @doc
%%%     格式装换
%%% @end
%%% Created : 26. 7月 2021 10:49
%%%-------------------------------------------------------------------
-module(format).
-author("liuwentao").

-export([
     gain_text/2
    , gain_text/3
    , gain_to_val/1
    , gain_to_val/2
    , loss_to_val/1
    , loss_to_val/2
    , gain_to_unbind_val/1
    , merge_gl/1
    , val_to_gain/1
    , val_to_loss/1
    , val_to_loss/2
    , merge_val/2
    , gain_item/2
]).

-include("common.hrl").
-include("role.hrl").
-include("item.hrl").
-include("gain.hrl").
-include("notice.hrl").
-include("assets.hrl").
-include("color.hrl").

%% @doc 损益数据信息格式
gain_text(L, Role) ->
    Opts = #gain_text_opts{gain_tag = ?gain_tag, loss_tag = ?loss_tag},
    gain_text(L, Opts, Role).

gain_text(#gain{val = 0}, _Opts, _Role) ->
    "";
gain_text(#loss{val = 0}, _Opts, _Role) ->
    "";
gain_text(
    L,
    Opts = #gain_text_opts{
        gain_tag = GainTag, loss_tag = LossTag,
        order = Order, split_op_str = SplitOp
    },
    Role
) when is_list(L) -> %% 损益格式组装
    GLStr =
        case split_gl(L, [], []) of
            Empty = {[], []} -> Empty;
            {GAcc, []} -> {gain_text(GAcc, Opts, Role, []), []};
            {[], LAcc} -> {[], gain_text(LAcc, Opts, Role, [])};
            {GAcc, LAcc} ->
                GStr = gain_text(GAcc, Opts, Role, []),
                LStr = gain_text(LAcc, Opts, Role, []),
                {GStr, LStr}
        end,
    case GLStr of
        {[], []} ->
            "";
        {Str, []} ->
            GainText = Str,
            notice:format("~ts~ts", [GainTag, GainText]);
        {[], Str} ->
            LossText = Str,
            notice:format("~ts~ts", [ LossTag, LossText]);
        {GainStr, LossStr} ->
            GainText = GainStr,
            LossText = LossStr,
            Args =
                case Order of
                    gain ->
                        [GainTag, GainText, SplitOp, LossTag, LossText];
                    loss ->
                        [ LossTag, LossText, SplitOp, GainTag, GainText]
                end,
            notice:format("~ts~ts~ts~ts~ts", Args)
    end;
%% 通用提示
gain_text(#gain{label = Label, val = Val}, _Opts, _Role) when is_atom(Label) ->
    ?S("{assets_1|~w|~w}", [assets_data:label_to_enum(Label), Val]);
gain_text(#loss{label = Label, val = Val}, _Opts, _Role) when is_atom(Label) ->
    ?S("{assets_1|~w|~w}", [assets_data:label_to_enum(Label), Val]);
gain_text(Unknow, _Opts, _Role) ->
    ?ERR("未知的损益格式[Unknow:~w]", [Unknow]),
    "".

%% @doc 损益数据组装
gain_text([], #gain_text_opts{split_str = SplitStr}, _Role, Acc) ->
    string:join(lists:reverse(Acc), SplitStr);
gain_text([H | T], Opts, Role, Acc) ->
    case gain_text(H, Opts, Role) of
        [] -> gain_text(T, Opts, Role, Acc);
        Str = [_ | _] ->
            gain_text(T, Opts, Role, [Str | Acc]);
        _False ->
            ?DEBUG("未知的损益格式[gl:~w][Err:~w]", [H, _False]),
            gain_text(T, Opts, Role, Acc)
    end;
gain_text(Unknow, _Opts, _Role, _Acc) ->
    ?ERR("未知的损益格式[Unknow:~w]", [Unknow]),
    "".

%% @doc 拆分损益类别
split_gl([], GainAcc, LossAcc) ->
    {lists:reverse(GainAcc), lists:reverse(LossAcc)};
split_gl([L = #loss{} | Rest], GainAcc, LossAcc) ->
    split_gl(Rest, GainAcc, [L | LossAcc]);
split_gl([G = #gain{} | Rest], GainAcc, LossAcc) ->
    split_gl(Rest, [G | GainAcc], LossAcc);
split_gl([_ | Rest], GainAcc, LossAcc) ->
    split_gl(Rest, GainAcc, LossAcc).

%% @doc 合并2个val列表
merge_val([], List) -> List;
merge_val([{K, V} | T], List) ->
    case lists:keyfind(K, 1, List) of
        false ->
            merge_val(T, [{K, V} | List]);
        {K, V1} ->
            merge_val(T, lists:keyreplace(K, 1, List, {K, V + V1}))
    end;
merge_val([{K, B, V} | T], List) ->
    case lists:keyfind(K, 1, List) of
        {K, B, V1} ->
            merge_val(T, lists:keyreplace(K, 1, List, {K, B, V + V1}));
        _ ->
            merge_val(T, [{K, B, V} | List])
    end;
merge_val([_Other | T], List) ->
    merge_val(T, List).


%% @doc 合并同类型的GL
merge_gl(GL) ->
    merge_gl(GL, [], []).

merge_gl([], GAcc, LAcc) ->
    {GAcc , LAcc};
merge_gl([H = #gain{} | T], GAcc, LAcc) ->
    merge_gl(T, [H | GAcc], LAcc);
merge_gl([H = #loss{} | T], GAcc, LAcc) ->
    merge_gl(T, GAcc, [H | LAcc]);
merge_gl([_ | T], GAcc, LAcc) ->
    merge_gl(T, GAcc, LAcc).


%% @doc 值列表数据转换成loss数据
-spec val_to_loss(list()) -> [#loss{}].
val_to_loss(ValList) ->
    val_to_loss(ValList, #{}, []).

val_to_loss(ValList, Opts) when is_map(Opts) ->
    val_to_loss(ValList, Opts, []);
val_to_loss(_ValList, Opts) ->
    ?ERR("第二个参数应为Map类型[Opts:~w]", [Opts]),
    [].

val_to_loss([], _Opts, L) -> L;
val_to_loss([{BaseId, _, Num} | T], Opts, L) ->
    val_to_loss([{BaseId, Num} | T], Opts, L);
val_to_loss([{Id, Val} | T], Opts, L) when Id >= ?assets_item_init_id andalso Id =< ?assets_item_end_id ->
    Label = assets_data:enum_to_label(Id),
    Msg = notice:format(?T("~ts不足, 无法操作"), [{string_2, ?color_red, assets_data:enum_to_name(Id)}]),
    Loss = #loss{label = Label, val = Val, msg = Msg},
    val_to_loss(T, Opts, [Loss | L]);
val_to_loss([{BaseId, Num} | T], Opts, L) ->
    Loss = #loss{label = item_group, val = [{BaseId, Num}], msg = notice:format(?T("~ts不足, 无法操作"), [{item_2, BaseId}])},
    val_to_loss(T, Opts, [Loss | L]);
val_to_loss([Error | T], Opts, L) ->
    Loss = #loss{label = loss_error, val = 99999, msg = notice:format(?T("消耗配置有误：~w"), [Error])},
    ?ERR("错误的转换格式 ~w ~n stacktrace~w", [Error, util:get_stacktrace()]),
    val_to_loss(T, Opts, [Loss | L]).

%% @doc 值列表数据转换成gain数据
-spec val_to_gain(list()) -> [#gain{}].
val_to_gain(ValList) ->
    val_to_gain(ValList, []).

val_to_gain([], Gains) -> Gains;
val_to_gain([{_Name, _Bind, 0} | T], Gains) ->
    val_to_gain(T, Gains);
val_to_gain([{_Name, 0} | T], Gains) ->
    val_to_gain(T, Gains);
val_to_gain([{BaseId, Val} | T], Gains) when BaseId < ?assets_item_init_id orelse BaseId > ?assets_item_end_id ->
    %% 默认绑定
    val_to_gain([{BaseId, ?true, Val} | T], Gains);
val_to_gain([{BaseId, Bind, Val} | T], Gains) when BaseId < ?assets_item_init_id orelse BaseId > ?assets_item_end_id ->
    case item_data:get(BaseId) of
        #item_base{} ->
            G = #gain{label = item_base_id, val = [{BaseId, Bind, Val}]},
            val_to_gain(T, [G | Gains]);
        _ ->
            ?ERR("不存在的道具,不予发放[~w]",[BaseId]),
            val_to_gain(T, Gains)
    end;
%% 资产ID
val_to_gain([{BaseId, _Bind, Val} | T], Gains) when BaseId >= ?assets_item_init_id  andalso BaseId =< ?assets_item_end_id ->
    val_to_gain([{BaseId, Val} | T], Gains);
val_to_gain([{Id, Val} | T], Gains) when Id >= ?assets_item_init_id andalso Id =< ?assets_item_end_id ->
    G = #gain{label = assets_data:enum_to_label(Id), val = Val},
    val_to_gain(T, [G | Gains]);
val_to_gain([_V | T], Gains) ->
    ?ERR("错误的数值,无法解析[~w] from:~w",[_V, util:get_stacktrace()]),
    val_to_gain(T, Gains).


%% @doc 奖励结构转换成val
gain_to_val([]) -> [];
gain_to_val(GainList = [#gain{} | _]) ->
    gain_to_val(GainList, []);
gain_to_val(_V) ->
    ?ERR("错误的奖励结构,无法解析[~w] util:~w", [_V, util:get_stacktrace()]),
    false.

gain_to_val([], Acc) -> Acc;
gain_to_val([Gain | Rest], Acc) ->
    case gain_to_val(Gain) of
        false ->
            gain_to_val(Rest, Acc);
        New when is_list(New) ->
            gain_to_val(Rest, New ++ Acc);
        New = {_, _} ->
            gain_to_val(Rest, [New | Acc]);
        New = {_, _, _} ->
            gain_to_val(Rest, [New | Acc])
    end.

gain_to_unbind_val(GainList) ->
    R = gain_to_val(GainList),
    [{BaseId, 0, Num} || {BaseId, Num} <- R].

loss_to_val(_V) ->
    ?ERR("错误的奖励结构,无法解析[~w]",[_V]),
    false.

loss_to_val([], Acc) -> Acc;
loss_to_val([Loss | Rest], Acc) ->
    case loss_to_val(Loss) of
        false -> loss_to_val(Rest, Acc);
        New = {_, _} -> loss_to_val(Rest, [New | Acc]);
        New when is_list(New) -> loss_to_val(Rest, New ++ Acc)
    end.


gain_item(L, Role) when is_list(L) andalso L =/= []-> gain_item(L, Role, []);
gain_item(L, _Role) -> ?ERR("未知的损益格式[Unknow:~w]", [L]), [].

gain_item([], _Role, ItemInfo) -> lists:reverse(ItemInfo);
gain_item([H|T], Role, ItemInfo) ->
    TransH =  gain_item_info(H, Role),
    case TransH of
        [] ->
            gain_item(T, Role, ItemInfo);
        _ ->
            gain_item(T, Role, TransH ++ ItemInfo)
    end.

gain_item_info(#gain{label = Label, val = Val}, _Role) when is_atom(Label)->
    case assets_data:label_to_enum(Label) of
        0 ->
            ?ERR("未知的损益格式[Unknow:~w]", [Label]),
            [];
        Id ->
            [{Id, Val}]
    end;
gain_item_info(#loss{}, _Role) -> [];
gain_item_info(Unknow, _Role) -> ?ERR("未知的损益格式[Unknow:~w]", [Unknow]), [].

